package com.jkt.rms.validator;

import java.util.Iterator;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.jkt.rms.business.Project;
import com.jkt.rms.businessservice.ProjectBusinessService;
import com.jkt.rms.commons.utils.StringUtils;
import com.jkt.rms.vo.ProjectVO;

public class ProjectValidator implements Validator {

	private ProjectBusinessService projectBusinessService;

	@Override
	public boolean supports(Class arg0) {
		return ProjectVO.class.equals(arg0);
	}

	public void setProjectBusinessService(
			ProjectBusinessService projectBusinessService) {
		this.projectBusinessService = projectBusinessService;
	}


	@Override
	public void validate(Object arg0, Errors errors) {
		ProjectVO projectVO = (ProjectVO) arg0;
		//check for empty/whitespace

		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "projectNumber", "error.mandatory.field", new String[]{"Project No"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "projectType", "error.mandatory.field", new String[]{"Project Type"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "projectName", "error.mandatory.field", new String[]{"Project Name"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "purchaseOrderNo", "error.mandatory.field", new String[]{"Purchase Order No"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "projectManager", "error.mandatory.field", new String[]{"Project Manager"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "deliveryManager", "error.mandatory.field", new String[]{"Delivery Manager"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "costCentre", "error.mandatory.field", new String[]{"Cost Centre"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lineOfBusiness", "error.mandatory.field", new String[]{"Line of Business"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "projectExpectedStartDate", "error.mandatory.field", new String[]{"Planned Start Date"});
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "projectExpectedEndDate", "error.mandatory.field", new String[]{"Planned End Date"});
		
		//check for unique validations
		uniqueValidations(projectVO, errors);
		
		//check for date validation
		//expectedStartDate should be < expectedEndDate  
		if(projectVO.getProjectExpectedStartDate() != null && projectVO.getProjectExpectedEndDate() != null 
				&& projectVO.getProjectExpectedStartDate().after(projectVO.getProjectExpectedEndDate())){
			errors.rejectValue("projectExpectedStartDate", "project.expectedstartdate.should.less.than.expectedenddate");
		}
		
		//actualStartDate should be < actualEndDate  
		if(projectVO.getProjectActualStartDate() != null && projectVO.getProjectActualEndDate() != null 
				&& projectVO.getProjectActualStartDate().after(projectVO.getProjectActualEndDate())){
			errors.rejectValue("projectActualStartDate", "project.actualstartdate.should.less.than.actualenddate");
		}
		
		//actualStartDate should not be > expectedEndDate  
		if(projectVO.getProjectActualStartDate() != null && projectVO.getProjectExpectedEndDate() != null 
				&& projectVO.getProjectActualStartDate().after(projectVO.getProjectExpectedEndDate())){
			errors.rejectValue("projectActualStartDate", "project.actualstartdate.should.not.greater.than.expectedenddate");
		}
		
		//actualStartDate should not be < expectedStartDate  
		if(projectVO.getProjectActualStartDate() != null && projectVO.getProjectExpectedStartDate() != null 
				&& projectVO.getProjectActualStartDate().before(projectVO.getProjectExpectedStartDate())){
			errors.rejectValue("projectActualStartDate", "project.actualstartdate.should.not.less.than.expectedstartdate");
		}
		
		//actualEndDate should not be < actualStartDate  
//		if(projectVO.getProjectActualStartDate() != null && projectVO.getProjectActualEndDate() != null 
//				&& projectVO.getProjectActualStartDate().after(projectVO.getProjectActualEndDate())){
//			errors.rejectValue("projectActualStartDate", "project.actualstartdate.should.not.be.greater.than.actualenddate");
//		}
		
		//validate projectNo should be alphanumeric
		if(projectVO.getProjectNumber() != null && !StringUtils.isAlphaNumeric(projectVO.getProjectNumber())){
			errors.reject("project.projectno.should.be.alphanumeric");
		}
		//validate projectName should be alphanumeric
		if(projectVO.getProjectName() != null && !StringUtils.isAlphaNumericWithSpace(projectVO.getProjectName())){
			errors.reject("project.projectname.should.be.alphanumericwithspace");
		}
		//validate purchaseOrderNo should be alphanumeric
		if(projectVO.getPurchaseOrderNo() != null && !StringUtils.isAlphaNumeric(projectVO.getPurchaseOrderNo())){
			errors.reject("project.purchaseorderno.should.be.alphanumeric");
		}
		//Project Manager should be contains alphabet and single quote
		if(projectVO.getProjectManager() != null && !StringUtils.isAlphabetSingleQuoteAndSpace(projectVO.getProjectManager())){
			errors.reject("project.projectmanager.should.be.alphabetsinglequoteandspace");
		}
		
		//Delivery Manager should be contains alphabet and single quote
		if(projectVO.getDeliveryManager() != null && !StringUtils.isAlphabetSingleQuoteAndSpace(projectVO.getDeliveryManager())){
			errors.reject("project.deliverymanager.should.be.alphabetsinglequoteandspace");
		}
		
		//validate costCentre
		if(projectVO.getCostCentre() != 0l){
			long value =  (long) projectVO.getCostCentre();
			if(value > 9999999999l){
				errors.reject("project.costcentre.outofrange");				
			}
		}else{
			errors.reject("project.costcentre.notzero");
		}
		
		//description's length can't be > 400
		if(projectVO.getProjectDescription() != null && projectVO.getProjectDescription().length() > 400){
				errors.reject("project.description.legth.over");				
		}
		
	}

	protected void uniqueValidations(ProjectVO projectVO, Errors errors) {
		//check for unique projectNo and purchaseOrderNo
		DetachedCriteria criteria = DetachedCriteria.forClass(Project.class)
		.add(Restrictions.or(Property.forName("projectNumber").eq(projectVO.getProjectNumber()),
				Property.forName("purchaseOrderNo").eq(projectVO.getPurchaseOrderNo())));
		
		//this handle unique validation in case of update Project
		if(projectVO.getId() != 0){
			criteria.add(Property.forName("id").ne(projectVO.getId()));
		}
		
		List<Project> list = projectBusinessService.findByCriteria(criteria);
		
		if(list != null && list.size() > 0){
			Iterator<Project> list_Iterator = list.iterator();
			while (list_Iterator.hasNext()) {
				Project project = list_Iterator.next();
				if(project.getProjectNumber() != null && projectVO.getProjectNumber() != null && project.getProjectNumber().equals(projectVO.getProjectNumber())){
					errors.rejectValue("projectNumber", "project.id.not.unique");
				}			
				if(project.getPurchaseOrderNo() != null && projectVO.getPurchaseOrderNo() != null && project.getPurchaseOrderNo().equals(projectVO.getPurchaseOrderNo())){
					errors.rejectValue("projectNumber", "project.purchaseorderno.not.unique");
				}			
			}
		}
	}
}
